<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        li {
            list-style: none;
        }

        .banner {
            width: 400px;
            height: 300px;
            margin: auto;
            position: relative;
            overflow: hidden;
        }

        .banner ul {
            width: 2000px;
            display: flex;
            position: absolute;
            left: 0;
        }

        .banner ul li {
            width: 400px;
            height: 300px;
            text-align: center;
            line-height: 300px;
            font-size: 50px;
            background-color: #f00;
        }

        span {
            width: 30px;
            height: 30px;
            text-align: center;
            line-height: 30px;
            background-color: #000;
            color: #fff;
            position: absolute;
            top: 0;
            bottom: 0;
            margin: auto;
        }

        .next {
            right: 0;
        }

        ol {
            position: absolute;
            width: 100%;
            bottom: 10px;
            display: flex;
            justify-content: center;
        }

        ol li {
            width: 20px;
            height: 20px;
            background-color: #ff0;
            margin: 10px;
        }

        .active {
            background-color: #0f0;
        }
    </style>
</head>

<body>

    <div class="banner">
        <ul>
            <li>1</li>
            <li>2</li>
            <li>3</li>
            <li>4</li>
            <li>1</li>
        </ul>
        <span class="prev">&lt;</span>
        <span class="next">&gt;</span>
        <ol>
            <li class="active"></li>
            <li></li>
            <li></li>
            <li></li>
        </ol>
    </div>

    <script>
        // 无缝轮播
        //    css部分   设置一个较大的Ul宽度
        //    移动ul这个位置

        //    实现：   在图片的最后面，复制第一张
        //             在最后一张图片(实际上也是第一张图片)播放完的瞬间切换到第一张

        //    bug1   页面失去焦点的时候，挂了 --- 只有定时器再按时跑  index和ul的位置会有延迟  --- 页面需要的资源分配给了已经获取焦点应用    

        //    bug2   点击过快的时候，图片来回切换  --- flag

        //    mov移动的速度要稍微快一点 ， autPlay自动播放的间隔时间尽量长一点



        var oBanner = document.querySelector('.banner');
        var oUl = oBanner.querySelector('ul');
        var oDots = oBanner.querySelectorAll('ol li');
        var oLis = oBanner.querySelectorAll('ul li');
        var _width = oBanner.offsetWidth;


        // 控制播放第几张
        var index = 0;
        // 定时器
        var t = null;

        // 防止点击过快
        var flag = true;

        for (var i = 0; i < oDots.length; i++) {
            oDots[i].index = i;
        }

        // 自动播放
        autoPlay();


        // 页面失去焦点以后
        window.onblur = function () {
            clearInterval(t);
        }

        window.onfocus = function () {
            autoPlay();
        }


        // 鼠标移入移出事件
        oBanner.addEventListener('mouseover', function () {
            clearInterval(t);
        })
        oBanner.addEventListener('mouseout', function () {
            autoPlay();
        })


        // 绑定点击事件
        oBanner.addEventListener('click', function (e) {
            // 上翻页
            if (e.target.className === 'prev') {
                if (flag) {
                    flag = false;
                    clearInterval(t);
                    if (index === 0) {
                        // 如果是第一张，就切换到最后一张(实际上还是第一张)
                        index = oLis.length - 1;
                        oUl.style.left = - index * _width + 'px';
                    }
                    index--;
                    move(oUl, 'left', -_width * index, 10, function () {
                        // 每一张图播放完了才可以点击下一张
                        flag = true;
                    });
                    showDot();
                    return
                }
            }

            // 下翻页
            if (e.target.className === 'next') {
                if (flag) {
                    flag = false;
                    clearInterval(t);
                    if (index === oLis.length - 1) {
                        // 如果是最后一张(实际上还是第一张),就切到实际的第一张
                        index = 0;
                        oUl.style.left = - index * _width + 'px';
                    }
                    index++;
                    move(oUl, 'left', -_width * index, 30, function () {
                        flag = true;
                    });
                    showDot();
                    return
                }
            }

            // 小点切换
            if (e.target.tagName === 'LI') {
                if (flag) {
                    flag = false;
                    clearInterval(t);
                    index = e.target.index;
                    move(oUl, 'left', -_width * index, 30, function () {
                        flag = true;
                    });
                    showDot();
                }
            }
        })


        function autoPlay() {
            t = setInterval(function () {
                index++;
                // oUl.style.left = -_width * index + 'px';
                move(oUl, 'left', -_width * index, 30, function () {
                    // 结束的瞬间切换到第一张
                    if (index === oLis.length - 1) {
                        index = 0;
                        oUl.style.left = 0;
                    }
                });
                showDot();
            }, 2000)
        }



        // 小点显示
        function showDot() {
            for (var i = 0; i < oDots.length; i++) {
                oDots[i].classList.remove('active');
            }
            if (index == oLis.length - 1) {
                oDots[0].classList.add('active');
            } else {
                oDots[index].classList.add('active');
            }

        }





        function move(ele, prop, end, speed, cb) {
            var cur = parseInt(getComputedStyle(ele)[prop]);
            speed = end > cur ? speed : -speed;
            var t = setInterval(function () {
                // console.log(speed);
                // 每次都在当前位置的基础上+20
                cur += speed;

                ele.style[prop] = cur + 'px';
                // 当前位置与终点位置的差值 在 20以内
                if (Math.abs(end - cur) <= Math.abs(speed)) {
                    clearInterval(t);
                    // 万一不能被20整除的时候，强制到达终点
                    ele.style[prop] = end + 'px';
                    cb && cb();
                }
            }, 10)
        }


    </script>

</body>

</html>